package com.logos.musicframe.service.impl;

import com.alibaba.fastjson.JSON;
import com.logos.musicframe.constant.RedisConstant;
import com.logos.musicframe.converter.UsersConverter;
import com.logos.musicframe.entity.Users;
import com.logos.musicframe.mapper.UsersMapper;
import com.logos.musicframe.req.UsersReq;
import com.logos.musicframe.resp.UsersResp;
import com.logos.musicframe.service.FileService;
import com.logos.musicframe.service.UsersService;
import com.logos.musicframe.utils.EncryptionUtil;
import com.logos.musicframe.utils.LocalSessionStorageUtil;
import com.logos.musicframe.utils.RandomStringUtil;
import com.logos.musicframe.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.nio.file.Files;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 用户信息表(Users)表服务实现类
 *
 * @author rose
 * @since 2025-06-01 21:06:01
 */
@Service("usersService")
@Slf4j
public class UsersServiceImpl implements UsersService {

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private FileService fileService;

    // 验证码有效期（分钟）
    private static final int CODE_EXPIRE_MINUTES = 5;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public UsersResp queryById(Integer id) {
        // 查询redis中是否存在
        if (redisUtil.exist(RedisConstant.USER_LOGIN_SESSION + id)) {
            String userRespStr = redisUtil.get(RedisConstant.USER_LOGIN_SESSION + id);
            log.info("usersService.queryById.Cache.Hit:" + userRespStr);
            return JSON.parseObject(userRespStr, UsersResp.class);
        }
        Users users = this.usersMapper.queryById(id);
        UsersResp usersResp = UsersConverter.INSTANCE.convertEntityToResp(users);
        // 解密手机号
        usersResp.setPhone(EncryptionUtil.maskPhoneNumber(usersResp.getPhone()));
        // 缓存当前登录用户信息
        redisUtil.set(RedisConstant.USER_LOGIN_SESSION + id, JSON.toJSONString(usersResp));
        return usersResp;
    }

    /**
     * 新增数据
     *
     * @param users 实例对象
     * @return 实例对象
     */
    @Override
    public Users insert(Users users) {
        this.usersMapper.insert(users);
        return users;
    }

    /**
     * 修改数据
     *
     * @param users 实例对象
     * @return 实例对象
     */
    @Override
    public Users update(Users users) {
        return null;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.usersMapper.deleteById(id) > 0;
    }

    @Override
    public UsersResp login(UsersReq usersReq) {
        Users users = UsersConverter.INSTANCE.convertReqToEntity(usersReq);
        users.setPassword(EncryptionUtil.encrypt(users.getPassword()));
        List<Users> userList = usersMapper.queryByCondition(users);
        if (userList != null && userList.size() == 1) {
            users = userList.get(0);
            // 解密手机号
            users.setPhone(EncryptionUtil.maskPhoneNumber(users.getPhone()));
            return UsersConverter.INSTANCE.convertEntityToResp(users);
        }
        // 试试手机号
        users.setPhone(EncryptionUtil.encrypt(users.getUsername()));
        users.setUsername(null);
        userList = usersMapper.queryByCondition(users);
        if (userList != null && userList.size() == 1) {
            users = userList.get(0);
            UsersResp usersResp = UsersConverter.INSTANCE.convertEntityToResp(users);
            LocalSessionStorageUtil.clearLoginSession();
            // 把手机号解密
            usersResp.setPhone(EncryptionUtil.maskPhoneNumber(users.getPhone()));
            // 保存信息到Redis中
            redisUtil.setNx(RedisConstant.USER_LOGIN_SESSION + users.getId(), JSON.toJSONString(usersResp), RedisConstant.EXPIRE_TIME_ONE_MONTH);
            LocalSessionStorageUtil.saveLoginSession(users.getId().toString(), JSON.toJSONString(usersResp));
            return usersResp;
        }
        return null;
    }

    @Override
    public Boolean register(UsersReq usersReq) {
        Users users = UsersConverter.INSTANCE.convertReqToEntity(usersReq);
        // 判断该手机号是否注册过了
        Users condition = new Users();
        condition.setPhone(EncryptionUtil.encrypt(users.getPhone()));
        List<Users> userList = usersMapper.queryByCondition(condition);
        if (userList != null && userList.size() > 0) {
            // 抛出异常
            return false;
        }
        // 设置用户名: 手机号后四位+'_'+随机几个英文字符
        users.setUsername(users.getPhone().substring(users.getPhone().length() - 4) + "_" + RandomStringUtil.randomFourLetters());
        users.setPassword(EncryptionUtil.encrypt(users.getPassword()));
        users.setPhone(EncryptionUtil.encrypt(users.getPhone()));
        users.setCreatedAt(new Date());
        int count = usersMapper.insert(users);
        return count > 0;
    }

    /**
     * 更新用户信息
     *
     * @param usersReq 用户信息请求对象
     * @return 是否更新成功
     */
    @Override
    public Boolean updateUserInfo(UsersReq usersReq) {
        // 转换为实体类
        Users users = UsersConverter.INSTANCE.convertReqToEntity(usersReq);

        // 加密手机号
        if (users.getPhone() != null && !users.getPhone().isEmpty()) {
            users.setPhone(EncryptionUtil.encrypt(users.getPhone()));
        }
        // 上传头像
        File avatar = usersReq.getAvatar();
        if (avatar != null && avatar.exists()) {
            String fileUrl = fileService.uploadFile(avatar);
            users.setAvatar(fileUrl);
        }
        // 更新用户信息
        int count = usersMapper.update(users);
        // 如果更新成功，清除缓存
        if (count > 0) {
            redisUtil.del(RedisConstant.USER_LOGIN_SESSION + users.getId());
        }
        return count > 0;
    }

    /**
     * 绑定手机号
     *
     * @param usersReq 包含手机号和验证码的请求对象
     * @return 是否绑定成功
     */
    @Override
    public Boolean bindPhone(UsersReq usersReq) {
        // 验证验证码是否正确
        String codeKey = RedisConstant.PHONE_CODE_PREFIX + usersReq.getPhone();
        if (!redisUtil.exist(codeKey)) {
            log.error("验证码已过期或不存在");
            return false;
        }
        String savedCode = redisUtil.get(codeKey);
        if (!savedCode.equals(usersReq.getCode())) {
            log.error("验证码不正确");
            return false;
        }
        // 检查手机号是否已被其他用户绑定
        Users condition = new Users();
        condition.setPhone(EncryptionUtil.encrypt(usersReq.getPhone()));
        List<Users> userList = usersMapper.queryByCondition(condition);
        if (userList != null && userList.size() > 0) {
            // 该手机号已被绑定
            log.error("手机号已被绑定");
            return false;
        }
        // 更新用户手机号
        Users users = new Users();
        users.setId(usersReq.getId());
        users.setPhone(EncryptionUtil.encrypt(usersReq.getPhone()));
        // 更新用户信息
        int count = usersMapper.update(users);
        // 如果更新成功，清除缓存和验证码
        if (count > 0) {
            redisUtil.del(RedisConstant.USER_LOGIN_SESSION + users.getId());
            redisUtil.del(codeKey);
            return true;
        }
        return false;
    }

    /**
     * 发送手机验证码
     *
     * @param phone 手机号
     * @return 是否发送成功
     */
    @Override
    public Boolean sendPhoneCode(String phone) {
        try {
            // 生成6位随机数字验证码
            String code = RandomStringUtil.getSmsCode();

            // 将验证码保存到Redis，设置过期时间
            String codeKey = RedisConstant.PHONE_CODE_PREFIX + phone;
            redisUtil.setNx(codeKey, code, RedisConstant.CODE_ONE_MINUTES);

            // 模拟发送短信
            log.info("向手机号 {} 发送验证码: {}", phone, code);

            // 实际项目中，这里应该调用短信服务商的API发送短信
            // 例如：smsService.sendSms(phone, "您的验证码是：" + code + "，有效期" + CODE_EXPIRE_MINUTES + "分钟，请勿泄露给他人。");

            return true;
        } catch (Exception e) {
            log.error("发送验证码失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * @param phone 手机号
     * @return 验证码
     */
    @Override
    public String getLastSentCode(String phone) {
        String codeKey = RedisConstant.PHONE_CODE_PREFIX + phone;
        if (redisUtil.exist(codeKey)) {
            return redisUtil.get(codeKey);
        }
        return null;
    }
}
